#include "StdAfx.h"
#include "..\Calibrator\Calibrator.h"
#include <string>
using namespace std;
Calibrator::Calibrator(void)
{
}

Calibrator::~Calibrator(void)
{
}

void Calibrator::InputFile(const string& filename)
{
	m_indata.LoadFile(filename);
}

void Calibrator::initialize()
{
	/**********************************************************************/
	// NCUC Model Section

	// set model pattern
	string pattern;
	m_indata.ModelConfiguration(pattern);
	m_model.config(pattern);

	// set watershed area
	double area;
	m_indata.area(area);
	m_model.area(area);

	// set time interval
	unsigned int interval;
	m_indata.TimeInterval(interval);
	m_model.interval(interval);
	
	// set the sill length and the corresponding boundaries
	double length;
	m_indata.SillLength(length);
	double lower;
	m_indata.SillLowerBound(lower);
	double upper;
	m_indata.SillUpperBound(upper);
	m_model.sillBound(lower, upper, static_cast<unsigned int> (length));
	// TO DO 
	// IMPLEMENT THE get the length of the binary string representing the vent coefficient
	m_model.ventBound(10);

	/**********************************************************************/
	// ACM Section
	// store the rainfall and the runoff data;
	vector<double> tmp;

	// set the observed runoff to be a part of the AttachedData of the ACMSimpleGAB2D
	tmp.clear();
 	m_indata.ObservedRunoff(tmp);
	m_acm.obsRunoff(tmp);

	// set the rainfall records to be a part of the AttachedData of the ACMSimpleGAB2D
	tmp.clear();
	m_indata.ObservedRainfall(tmp);
	m_acm.rainfall(tmp);
	
	// assign the model
	m_acm.model(&m_model);
	
	// assign the genome information for the ACMSimpleGAB2D
	m_acm.configure(
		m_model.genome(), coe
		);
	
	// initialize
	m_acm.initialize();
	
	// probability of crossover
	double p;
	m_indata.pCrossOver(p);
	m_acm.pCrossover(p);

	// probability of mutation
	m_indata.pMutation(p);
	m_acm.pMutation(p);

	// population size
	unsigned int n;
	m_indata.nPopulation(n);
	m_acm.nPopulation(n);

	// number of generations
	m_indata.nGeneration(n);
	m_acm.nGeneration(n);

	// maximize
	m_acm.maximize();

	// TO DO
	// Let user choose their own Objectve evaluation function
}

void Calibrator::evolve()
{
	m_acm.evolve();
}
// get optimal parameters and write it to the file
void Calibrator::OptimalParameters()
{
	m_outdata.ModelParameters(
		m_acm.bestIndividual()
		);
}

const vector<double> Calibrator::OptimalRunoff()
{
	vector<double> optimum = m_acm.bestIndividual();
	m_model.parameters(optimum);
	
	vector<double> rainfall;
	rainfall.clear();
	m_indata.ObservedRainfall(rainfall);

	vector<double> runoff = m_model.runoff(rainfall);
	return runoff;
}

// calculate the runoff using the optimal model parameters according to the optionl rainfall
const vector<double> Calibrator::OptionalRunoff()
{
	vector<double> optimum = m_acm.bestIndividual();
	m_model.parameters(optimum);
	
	vector<double> rainfall;
	rainfall.clear();
	m_indata.OptionalRainfall(rainfall);

	vector<double> runoff = m_model.runoff(rainfall);
	return runoff;
}


// get the runoff calculated using the optimal parameters. That is the runoff during the calibration
void Calibrator::RunoffCalibration()
{
	m_outdata.RunoffCalibration(
		OptimalRunoff()
		);
}

// write the runoff calculated using the optimal parameters to the file. That is the runoff during the validation
void Calibrator::RunoffValidation()
{
	m_outdata.RunoffValidation(
		OptionalRunoff()
		);
}
// calculate the CE value of the calibration and write to the file
const double Calibrator::CE()
{
	vector<double> obsRunoff;
	m_indata.ObservedRunoff(obsRunoff);

	double ce = coe(OptimalRunoff(), obsRunoff);
	m_outdata.CECalibration(ce);

	obsRunoff.clear();
	m_indata.OptionalRunoff(obsRunoff);
	ce = coe(OptionalRunoff(), obsRunoff);
	m_outdata.CEValidation(ce);
	return ce;
}

// save file
void Calibrator::SaveFile(const string& filename)
{
	OptimalParameters();
	RunoffCalibration();
	RunoffValidation();
	CE();
	m_outdata.SaveFile(filename);
}

void Calibrator::Run(const string& infilename, const string& outfilename)
{
	InputFile(infilename);
	initialize();
	evolve();
	m_outdata.BaseFile(infilename.c_str());
	SaveFile(outfilename);
}
	